RippleSLControls{

	var 
	controlsList,// OrderedEnvironment
	parent,
	descriptor, // a list of all the controls for this voices
	keys,
	arr,
	midiControlNumbers;  // 0 - 127. dictionary which maps midi channels to controls
	
	getValue{|controlArg|
		if(
			controlsList.at(controlArg) != nil,
			{^controlsList.at(controlArg).getValue},
			{^nil}
		);
	}
	
	getDescriptor{
		^descriptor;	
	}
	
	setMidiControlNumbers{|midiCN|
		midiControlNumbers = midiCN;	
	}
	
	
	setDescriptor{|desc|
		descriptor = desc;	
	}
	
	setParent{|parentArg|
		parent = parentArg;
	}
	
	setValPostLaunch{|name, val|
		parent.setControlValPostLaunch(name, val);
	}
	
	setValue{|controlArg, valueArg, subControlArg|
		var control;

		control = controlsList.at(controlArg);
		
		
		if(control == nil){
			^false;
		};
		
		if(control != nil){			
			if(subControlArg == nil){
				control.setValue(valueArg);
				^nil;
			};
			if(subControlArg == \Rand){
				controlsList.at(controlArg).setRandValue(valueArg);
			}
		}
		
		^true;
	}
	
	
	setValueMidi{|midicontrolNumber, valArg|
		var controlToSet, val;
		
		val =  valArg/128;
		
		controlToSet = midiControlNumbers.at(midicontrolNumber);
		
		if(controlToSet != nil){
			this.setValue(controlToSet.getName, val);
			parent.setControlGuiValue(controlToSet.getName, val);
		};
		
		
	}
	
	// called when gui launches, so that gui is automatically updated with correct info
	sendAllValues{
		controlsList.keysValuesDo{|key, control|
			parent.setControlGuiValue(key, control.getOneToZeroValue, nil);
			parent.setControlGuiValue(key, control.getRandAmt, \Rand);
			parent.setControlGuiValue(key, control.hasPlugins, \PluginButton);
		}	
	}
	
	setControlsList{|controlsListArg|
		controlsList = controlsListArg;
	}
	
	getAsArgsArray{
		arr = Array.new(controlsList.size * 2); 
		
		controlsList.keysValuesDo{|name, control|
			arr.add(name);
			arr.add(control.getValue);
		};
		^arr;	
	}
	
	getCachedArgsArrayDescaled{
	
		arr = Array.new(controlsList.size * 2); 
		
		controlsList.keysValuesDo{|name, control|
			arr.add(name);
			arr.add(controlsList.at(name).descaleValue(control.getLastReturnedS));
		};
		^arr;
	}
	
	getCachedValue{|controlName|
		^controlsList.at(controlName).getLastReturnedS;
	}
	
	getOneToZeroValue{|controlName|
		var control;
		control = controlsList.at(controlName);
		^control.getOneToZeroValue;
	}
	
	recieveControlChange{|name, value|
	
	}
	
	beats{ // placeholder. refactor this
	
	}
	
	displayPluginGui{|name|
		controlsList.at(name).displayPluginGui;
	}
	
	addPlugin{|name, plugin|
		^controlsList.at(name).addPlugin(plugin);
	}
	
	refreshGui{
		parent.refreshGui;
	}
	
	setControlGuiValue{|nameArg, valArg, subControlArg|
		parent.setControlGuiValue(nameArg, valArg, subControlArg);
	}
	

	resetPlugins{
		controlsList.keysValuesDo{|name, control|
			control.resetPlugins;
		};	
	}
	
	accept{|xb|
		controlsList.keysValuesDo{|name, control|
			var controlXb;
			controlXb = XMLNodeBuilder.new;
			controlXb.setParent(xb.getNode);
			control.accept(controlXb);
		};		
	}
	
	exists{|name|
		if( controlsList.at(name).notNil,{
			^true;
		},{
			^false;
		}
		
		)
	}

}
